#include "../include/Server.hpp"

#define NOBLOCK
#define BUF_SIZE 2048

struct Impl_Server{
    int server_fd;
    int epfd;  // Server's epoll's filefd.
    int listen_num;  // Decide listen's size and epoll's event size.
    struct sockaddr_in server_addr;
    unsigned int PORT;
    struct epoll_event *events;  // this is epool's events. it's size look listen_nums.
    Impl_Server(unsigned int port,int listen_num):PORT(port),listen_num(listen_num){};
};

void getBUF(int fd){
    int snd_size=0;
    socklen_t optlen;
    optlen=sizeof(snd_size);
    int err=getsockopt(fd,SOL_SOCKET,SO_SNDBUF,&snd_size,&optlen);
    std::cout<<"send size:"<<snd_size<<std::endl;
}

void setBUF(int fd){
    getBUF(fd);
    int size=1024*1024*100;
    int ret_flag;
    ret_flag=setsockopt(fd,SOL_SOCKET,SO_SNDBUF,(char*)&size,sizeof(size));
    getBUF(fd);
}

const int Server::get_server_fd() const{
        return pimpl->server_fd;
}
int Server::get_server_fd(){
    return pimpl->server_fd;
}
int Server::get_epfd(){
    return pimpl->epfd;
}
// void Server_accept(void); // listen connect.
Server::~Server(){
    delete[] pimpl->events;
}

static void Server_accept(Server* self){
    while(true){
        printf("accept...\n");
        static struct epoll_event ev;
        #ifdef BLOCK
        ev.data.fd=accept(self->get_server_fd(),NULL,NULL);  // 阻塞IO
        #endif

        #ifdef NOBLOCK
        ev.data.fd=accept4(self->get_server_fd(),NULL,NULL,SOCK_NONBLOCK);  // 非阻塞IO
        #endif
        ev.events=EPOLLIN | EPOLLET |EPOLLOUT;
        if(epoll_ctl(self->get_epfd(),EPOLL_CTL_ADD,ev.data.fd,&ev)<0){
            printf("add epoll bad...\n");
        }
    }
}

static void Server_Accept(int fd,int epfd){
    struct epoll_event ev;
    // ev.data.fd=accept(fd,NULL,NULL);
    // ev.data.fd=accept4(fd,NULL,NULL,SOCK_NONBLOCK);

     #ifdef BLOCK
    ev.data.fd=accept(fd,NULL,NULL);  // 阻塞IO
    #endif

    #ifdef NOBLOCK
    ev.data.fd=accept4(fd,NULL,NULL,SOCK_NONBLOCK);  // 非阻塞IO
    #endif

    ev.events=EPOLLIN | EPOLLET |EPOLLOUT;
    if(epoll_ctl(epfd,EPOLL_CTL_ADD,ev.data.fd,&ev)<0){
        tprint("add epoll bad...\n");
    }
}


Server::Server(int port,int listen_num){
    pimpl=std::shared_ptr<Impl_Server>(new Impl_Server(port,listen_num));
    pimpl->events=new(std::nothrow) epoll_event[listen_num+1];
    if(pimpl->events==nullptr){
        tprint("Server init bad. events new bad.\n");
        abort();
    }
    pimpl->epfd=epoll_create(10);
    if(pimpl->epfd<0){
        tprint("epfd create bad...\n");
        delete[] pimpl->events;
        abort;
    }
    tprint("init...\n");
}

int Server::run(){
    #ifdef BLOCK
    pimpl->server_fd=socket(AF_INET,SOCK_STREAM,0);
    #endif
    #ifdef NOBLOCK
    pimpl->server_fd=socket(AF_INET,SOCK_STREAM | SOCK_NONBLOCK,0);
    #endif

    setBUF(pimpl->server_fd);

    in_addr_t s;
    inet_pton(AF_INET,"0.0.0.0",(void*)&s);
    pimpl->server_addr.sin_addr.s_addr=s;
    pimpl->server_addr.sin_family=AF_INET;
    pimpl->server_addr.sin_port=htons(pimpl->PORT);
    
    if(bind(pimpl->server_fd,(sockaddr*)&pimpl->server_addr,sizeof(pimpl->server_addr))<0){
        tprint("bind err...\n");
        return -1;
    }
    if(listen(pimpl->server_fd,1024)<0){
        tprint("listen err...\n");
        return -1;
    }

    struct epoll_event ev;
    ev.events=EPOLLIN;
    ev.data.fd=pimpl->server_fd;
    epoll_ctl(get_epfd(),EPOLL_CTL_ADD,get_server_fd(),&ev);
    // std::thread t_accept(Server_accept,this);
    if(request()<0){
        return -1;
    }
    // t_accept.join();
    return 0;
}

int test_sum=0;
int Server::request(){
    char buf[BUF_SIZE+1];   // 必须留足一位填补 \0 否则会有乱码
    while(1){
        int nfds=epoll_wait(pimpl->epfd,pimpl->events,pimpl->listen_num,-1);
        if(nfds<0){
            printf("epoll_wait error...[%d][%s]\n",nfds,strerror(errno));
            abort();
            return -1;
        }
        // RequestHead rhead;
        for(int i=0;i<nfds;i++){
            memset(buf,0,sizeof(buf));
            int tmp_epoll_fd=pimpl->events[i].data.fd;
            // epoll 触发accept 
            if(tmp_epoll_fd==get_server_fd()){
                Server_Accept(pimpl->server_fd,pimpl->epfd);
                continue;
            }else if(pimpl->events[i].events & EPOLLIN){
                std::string s;
                int bj;
                #ifdef NOBLOCK
                do{
                #endif
                    memset(buf,0,BUF_SIZE);
                    bj=read(tmp_epoll_fd,buf,BUF_SIZE);
                    s+=buf;
                #ifdef NOBLOCK
                }while(bj>0);
                #endif
                if(bj==0){
                    DBGprint("client close...\n");
                    epoll_ctl(pimpl->epfd,EPOLL_CTL_DEL,tmp_epoll_fd,&pimpl->events[i]);
                    close(tmp_epoll_fd);
                }

                // read(tmp_epoll_fd,buf,sizeof(buf));
                // std::shared_ptr<RequestHead> rhead(new(std::nothrow) RequestHead);
                std::shared_ptr<HttpRequest> req(new(std::nothrow) HttpRequest());
                
                req->tryDecode(s);
                // add(buf,sizeof(buf),rhead);
                std::shared_ptr<HTTP> http(new(std::nothrow) HTTP(tmp_epoll_fd,pimpl->epfd,&pimpl->events[i],req));
                // char xybuf[]="HTTP/1.1 200 OK\r\nContent-Type:text/html\r\nContent-Lent:6\r\n\nHello";
                // write(tmp_epoll_fd,xybuf,sizeof(xybuf));
                http->reuqest();
            }else{
                DBGprint("epoll error...\n");
            }
            
        }
    }
    return 0;
}


                // HttpRequest req;
                // std::cout<<"[method]"<<req->getMethod()<<std::endl;
                // std::cout<<std::endl;
                // std::cout<<"[url]"   <<req->getUrl()<<std::endl;
                // std::cout<<std::endl;
                // std::cout<<"[request params]"<<std::endl;
                // std::cout<<std::endl;
                // for(auto& p:req->getRequestParams()) 
                // {
                //     std::cout<<"   key: "  << p.first<<std::endl;
                //     std::cout<<"   value: "<< p.second<<std::endl;
                // }
                // std::cout<<std::endl;
                // std::cout<<"[protocol]"<<req->getProtocol() <<std::endl;
                // std::cout<<"[version]" <<req->getVersion()  <<std::endl;
                // std::cout<<std::endl;
                // std::cout<<"[request headers]" << std::endl;
                // for(auto& h : req->getHeaders()) {
                //     std::cout<<"   key: "   <<h.first  <<std::endl;
                //     std::cout<<"   value: " <<h.second <<std::endl;
                // }
                // std::cout<<std::endl;
                // std::cout<<"[body]"<<req->getBody()<<std::endl;